package com.huashiai.videocall.signal.service.impl;

import com.corundumstudio.socketio.SocketIOClient;
import com.corundumstudio.socketio.SocketIOServer;
import com.huashiai.videocall.signal.entity.RoomContainer;
import com.huashiai.videocall.signal.service.SocketIOService;
import com.onlyxiahui.common.message.push.PushMessage;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author XDD
 * @project oim-server
 * @date 2021/4/24
 * @description Good Good Study,Day Day Up.
 */

@Slf4j
@Service(value = "socketIOService")
public class SocketIOServiceImpl implements SocketIOService {


    @Autowired
    private RoomContainer roomContainer;

    @Autowired
    private SocketIOServer socketIOServer;

    /**
     * Spring IoC容器创建之后，在加载SocketIOServiceImpl Bean之后启动
     * @throws Exception
     */
    @PostConstruct
    private void autoStartup() throws Exception {
        start();
    }

    /**
     * Spring IoC容器在销毁SocketIOServiceImpl Bean之前关闭,避免重启项目服务端口占用问题
     * @throws Exception
     */
    @PreDestroy
    private void autoStop() throws Exception  {
        stop();
    }

    @Override
    public void start() {
        // 监听客户端连接
        socketIOServer.addConnectListener(client -> {
            log.info("客户端连接");
        });

        // 监听客户端断开连接
        socketIOServer.addDisconnectListener(client -> {

            roomContainer.removePerson(client);
            client.disconnect();
            log.info("客户端断开连接");
        });

        // 处理自定义的事件，与连接监听类似
        socketIOServer.addEventListener(JOIN, Map.class, (client, data, ackSender) -> {
            String room = data.get("room").toString();
            if(room==null){
                return;
            }
            List<String> otherPeron = roomContainer.addPerson(room,client);
            Map<String,Object> respon = new HashMap();
            respon.put("room",room);
            respon.put("peers",otherPeron);
            client.sendEvent("joined",respon);
            log.info("加入{}房间成功",room);
        });

        // 处理自定义的事件，与连接监听类似
        socketIOServer.addEventListener(SIGNAL, Map.class, (client, data, ackSender) -> {
            String from = (String) data.get("from");
            String to = (String) data.get("to");
            Object signal = data.get("signal");

            if(!client.getSessionId().toString().equals(from)){
                return;
            }

            SocketIOClient toClient = RoomContainer.selectByClientId(to);
            if(toClient!=null){
                Map<String,Object> respon = new HashMap<>();
                respon.put("from",from);
                respon.put("to",to);
                respon.put("signal",signal);
                toClient.sendEvent("signal",respon);
                log.info("signal发送完毕");
            }

        });

        // 处理自定义的事件，与连接监听类似
        socketIOServer.addEventListener(STATUS, Map.class, (client, data, ackSender) -> {
            log.info("STATUS事件发生");
        });
        socketIOServer.start();
    }

    @Override
    public void stop() {
        if (socketIOServer != null) {
            socketIOServer.stop();
            socketIOServer = null;
        }
    }

    @Override
    public void pushMessageToUser(PushMessage pushMessage) {
        System.out.println(pushMessage);
    }




    /**
     * 此方法为获取client连接中的参数，可根据需求更改
     * @param client
     * @return
     */
    private String getParamsByClient(SocketIOClient client) {
        // 从请求的连接中拿出参数（这里的loginUserNum必须是唯一标识）
        Map<String, List<String>> params = client.getHandshakeData().getUrlParams();
        List<String> list = params.get("loginUserNum");
        if (list != null && list.size() > 0) {
            return list.get(0);
        }
        return null;
    }
}

